﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Abp.Dependency;
using Abp.Runtime.Caching;
using Castle.Core.Internal;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Composite;
using Microsoft.Extensions.Primitives;

namespace KelonProud.Mvc.ViewEngine
{
    public class KelonProudViewVirtualPathProvider : IFileProvider
    {
        public IDirectoryContents GetDirectoryContents(string subpath)
        {
            if (subpath.IsNullOrEmpty() || subpath == "/")
            {
                return new CompositeDirectoryContents(new List<IFileProvider>(){new KelonProudViewVirtualPathProvider()},subpath );
            }
            else
            {
                return  new NotFoundDirectoryContents();
            }
        }

        public IFileInfo GetFileInfo(string subpath)
        {
            if (IsEmbeddedView(subpath))
            {
                return new KelonProudVirtualPathFileInfo(subpath);
            }
            else
            {
                return new NotFoundFileInfo(subpath);
            }
        }

        public IChangeToken Watch(string filter)
        {
            return  new KelonProudVirtualPathChangeToken(filter);
        }


        private bool IsEmbeddedView(string virtualPath)
        {
            if (string.IsNullOrEmpty(virtualPath))
                return false;

            string virtualPathAppRelative = "~"+ virtualPath;
            if (!virtualPathAppRelative.StartsWith("~/Views/", StringComparison.InvariantCultureIgnoreCase))
                return false;
            var fullyQualifiedViewName = virtualPathAppRelative.Substring(virtualPathAppRelative.LastIndexOf("/", System.StringComparison.Ordinal) + 1, virtualPathAppRelative.Length - 1 - virtualPathAppRelative.LastIndexOf("/", System.StringComparison.Ordinal));
            var result = GetViewMetadata(fullyQualifiedViewName);

            return result != null;
        }


        private ViewMetaData GetViewMetadata(string fullViewName)
        {
            var index = fullViewName.ToLower().IndexOf(".views", System.StringComparison.Ordinal);

            if (index == -1)
                return null;

            var assemblyName = fullViewName.Substring(0, index).ToLower();
            var assembly = GetAssembly(assemblyName);
            var stream = assembly.GetManifestResourceStream(fullViewName);

            if (stream != null)
                return new ViewMetaData()
                {
                    Name = fullViewName,
                    AssemblyFullName = assemblyName
                };
            else
                return null;
        }

        private Assembly GetAssembly(string assemblyName)
        {
            var cashManager = IocManager.Instance.Resolve<ICacheManager>();
            var cash = cashManager.GetCache("viewCash");
            var assembly = cash.GetOrDefault(assemblyName) as Assembly;


            if (assembly != null) return assembly;

            //.netCore 
            //assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyName);
            assembly = Assembly.Load(assemblyName);
            cash.Set(assemblyName, assembly);

            return assembly;
        }
    }
}
